package com.luych.toolbox.data.service.job;

import com.luych.toolbox.common.enums.DataBackupHistoryStatus;
import com.luych.toolbox.common.enums.DataBackupHistoryType;
import com.luych.toolbox.common.enums.DataBackupPlanStatus;
import com.luych.toolbox.data.service.constant.Constant;
import com.luych.toolbox.data.service.dao.DataBackupHistoryDao;
import com.luych.toolbox.data.service.dao.DataBackupPlanDao;
import com.luych.toolbox.data.service.entity.DataBackupHistory;
import com.luych.toolbox.data.service.entity.DataBackupPlan;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

public class DataBackupPlanExecuteJob extends QuartzJobBean {
    private static final Logger LOGGER = LoggerFactory.getLogger(DataBackupPlanExecuteJob.class);

    private final Scheduler scheduler;

    private final DataBackupPlanDao dataBackupPlanDao;
    private final DataBackupHistoryDao dataBackupHistoryDao;

    public DataBackupPlanExecuteJob(Scheduler scheduler, DataBackupPlanDao dataBackupPlanDao,
                                    DataBackupHistoryDao dataBackupHistoryDao) {
        this.scheduler = scheduler;
        this.dataBackupPlanDao = dataBackupPlanDao;
        this.dataBackupHistoryDao = dataBackupHistoryDao;
    }

    private JobDetail getJobDetail(String id) {
        Map<String, Object> jobParam = new HashMap<String, Object>() {{
            this.put("id", id);
        }};
        return JobBuilder.newJob(DataBackupHistoryExecuteJob.class)
                .withIdentity(id, DataBackupHistoryExecuteJob.class.getName())
                .usingJobData(new JobDataMap(jobParam))
                .build();
    }

    private Trigger getJobTrigger(String id) {
        return TriggerBuilder.newTrigger()
                .withIdentity(id, DataBackupHistoryExecuteJob.class.getName())
                .withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(1, 1))
                .build();
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        String id = context.getJobDetail().getJobDataMap().getString("id");

        DataBackupPlan dataBackupPlan = dataBackupPlanDao.findById(id).orElseThrow(() ->
                new JobExecutionException(Constant.DATA_BACKUP_PLAN_NOT_FOUND));

        if (DataBackupPlanStatus.DISABLE.equals(dataBackupPlan.getStatus())) {
            LOGGER.warn("the data backup plan[{}] is disabled, but still run in quartz, why ???", dataBackupPlan.getId());
            return;
        }

        String datetime = new SimpleDateFormat("yyyyMMdd.HHmmss").format(new Date());
        String backupFile = dataBackupPlan.getFile() + "." + datetime + ".backup";

        DataBackupHistory backupHistory = new DataBackupHistory();
        backupHistory.setId(UUID.randomUUID().toString());
        backupHistory.setCreateUserId(dataBackupPlan.getCreateUserId());
        backupHistory.setCreateDate(new Date());
        backupHistory.setName(dataBackupPlan.getName());
        backupHistory.setType(DataBackupHistoryType.SCHEDULE);
        backupHistory.setStatus(DataBackupHistoryStatus.LOADING);
        backupHistory.setFile(backupFile);
        backupHistory.setDataSourceId(dataBackupPlan.getDataSourceId());
        backupHistory.setDataAgentId(dataBackupPlan.getDataAgentId());
        backupHistory.setDataBackupPlanId(dataBackupPlan.getId());
        backupHistory.setOwnerId(dataBackupPlan.getOwnerId());
        dataBackupHistoryDao.save(backupHistory);

        LOGGER.info("start to schedule data backup plan [{}]...", dataBackupPlan.getName());
        try {
            scheduler.scheduleJob(this.getJobDetail(backupHistory.getId()), this.getJobTrigger(backupHistory.getId()));
            LOGGER.info("success to schedule data backup plan [{}]", dataBackupPlan.getName());
        } catch (SchedulerException e) {
            LOGGER.info("error to schedule data backup plan [{}]: {}", dataBackupPlan.getName(), e.getMessage(), e);
            throw new JobExecutionException(e);
        }
    }
}
